package model

import (
	"community_end/utils/errmsg"
	"golang.org/x/crypto/bcrypt"
	"gorm.io/gorm"
)

type User struct {
	gorm.Model
	Username    string `json:"username"`
	Alias       string `json:"alias"`
	Password    string
	Email       string
	Score       int `json:"score"`
	Posts       []Post
	TopicCount  int       `json:"topic_count"`
	FollowCount int       `json:"follow_count"`
	Follows     []*User   `gorm:"many2many:user_follows"`
	Comments    []Comment `gorm:"foreignKey:UserID"`
}

func (User) TableName() string {
	return "user"
}

func InsertUser(user *User) int {
	code := CheckUsername(user.Username)
	if code != errmsg.SUCCESS {
		return code
	}

	code = CheckEmail(user.Email)
	if code != errmsg.SUCCESS {
		return code
	}

	user.Password = encryption(user.Password)
	err := db.Debug().Create(user).Error
	if err != nil {
		return errmsg.USER_REGISTER_FAILED
	}
	return errmsg.SUCCESS
}

// 密码加密
func encryption(password string) string {
	// 传入明文密码，进行加密，之后存储到数据库中
	hash, _ := bcrypt.GenerateFromPassword([]byte(password), bcrypt.DefaultCost) // 加密处理
	return string(hash)
}

// 密码解密
func decrypt(encryptPwd string, password string) error {
	// 数据库中查询到加密后的密码，和用户输入的明文密码进行比较
	return bcrypt.CompareHashAndPassword([]byte(encryptPwd), []byte(password))
}

// 检查用户名
func CheckUsername(username string) int {
	var user User
	_ = db.Where("username = ?", username).Find(&user).Error
	if user.Username != "" {
		return errmsg.USER_REGISTER_USERNAME_FAILED
	}
	return errmsg.SUCCESS
}

// 检查邮箱
func CheckEmail(email string) int {
	var user User
	db.Where("email = ?", email).Find(&user)
	if user.Username != "" {
		return errmsg.USER_REGISTER_EMAIL_FAILED
	}
	return errmsg.SUCCESS
}

// 根据用户名查询用户
func SelectUserByUsername(username string, password string) int {
	var user User
	err := db.Where("username = ?", username).Find(&user).Error
	if err != nil {
		return errmsg.USER_NAME_OR_PASS_FAILED
	}

	err = decrypt(user.Password, password)
	if err != nil {
		return errmsg.USER_NAME_OR_PASS_FAILED
	}
	return errmsg.SUCCESS
}

func SelectUser(username string) (User, int) {
	var user User
	err := db.Preload("Posts").Where("username = ?", username).Find(&user).Error
	if err != nil {
		return User{}, errmsg.ERROR
	}
	return user, errmsg.SUCCESS
}

func SelectUserByID(id int) (*User, int) {
	user := &User{}
	err := db.Where("id = ?", id).Find(&user).Error
	if err != nil {
		return nil, errmsg.USER_SELECT_FAILED
	}
	return user, errmsg.SUCCESS
}

func UpdateUser(m map[string]interface{}, id string) int {
	err := db.Model(&User{}).Where("id = ?", id).Updates(m).Error
	if err != nil {
		return errmsg.USER_UPDATE_FAILED
	}
	return errmsg.SUCCESS
}

func SaveUser(user *User) int {
	err := db.Save(user).Error
	if err != nil {
		return errmsg.USER_UPDATE_FAILED
	}
	return errmsg.SUCCESS
}
